package com.ecoolex.discount.sales.core.manager;

import com.ecoolex.discount.sales.core.dao.DiscountProductDAO;
import com.ecoolex.discount.sales.entity.DiscountBrand;
import com.ecoolex.discount.sales.entity.DiscountProductExample;
import com.ecoolex.discount.sales.entity.DiscountProductWithBLOBs;
import com.ecoolex.discount.sales.entity.DiscountProductWithBLOBs.Column;
import com.ecoolex.discount.sales.enums.*;
import com.ecoolex.discount.sales.pojo.*;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.pojo.Sortings;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Date;
import java.util.List;

import static com.ecoolex.discount.sales.entity.DiscountProduct.IS_DELETED;
import static com.ecoolex.discount.sales.entity.DiscountProduct.NOT_DELETED;

@Service
public class DiscountProductManager {
    @Autowired
    private DiscountProductDAO dao;

    @Autowired
    private DiscountBrandManager discountBrandManager;
    @Autowired
    private DiscountProductGiftCardManager discountProductGiftCardManager;
    @Autowired
    private DiscountProductVouchersManager discountProductVouchersManager;
    @Autowired
    private DiscountProductRechargeManager discountProductRechargeManager;

    public Long countService(DiscountProductServiceType serviceType, String serviceDataId) {
        DiscountProductExample example = new DiscountProductExample();
        DiscountProductExample.Criteria criteria = example.createCriteria();

        criteria.andServiceTypeEqualTo(serviceType.real())
                .andDeletedEqualTo(NOT_DELETED);

        if (Check.notNullOrTrimEmpty(serviceDataId)) {
            criteria.andServiceDataIdEqualTo(serviceDataId);
        }

        return dao.countByExample(example);
    }

    public DiscountProductWithBLOBs getById(Integer productId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(productId, NOT_DELETED);
    }

    public Pagination<DiscountProductWithBLOBs> query(QueryDiscountProductDTO query, Sorting[] sorts, Page page) {
        DiscountProductExample example = new DiscountProductExample();
        DiscountProductExample.Criteria criteria = example.createCriteria();

        if (Check.notNull(query.getBrandId())) {
            criteria.andBrandIdEqualTo(query.getBrandId());
        }
        if (Check.notNull(query.getRegionType())) {
            criteria.andRegionTypeEqualTo(query.getRegionType());
        }
        if (Check.notNull(query.getDiscountMode())) {
            criteria.andDiscountModeEqualTo(query.getDiscountMode());
        }
        if (Check.notNull(query.getServiceType())) {
            criteria.andServiceTypeEqualTo(query.getServiceType());
        }
        if (Check.notNullOrTrimEmpty(query.getServiceDataId())) {
            criteria.andServiceDataIdEqualTo(query.getServiceDataId());
        }
        if (Check.notNullOrTrimEmpty(query.getName())) {
            criteria.andNameLike('%' + query.getName() + '%');
        }
        if (Check.notNullOrTrimEmpty(query.getSubTitle())) {
            criteria.andSubTitleLike('%' + query.getSubTitle() + '%');
        }
        if (Check.notNull(query.getBrandWeight())) {
            criteria.andBrandWeightEqualTo(query.getBrandWeight());
        }
        if (Check.notNull(query.getIsNew())) {
            criteria.andIsNewEqualTo(query.getIsNew());
        }
        if (Check.notNull(query.getStatus())) {
            criteria.andStatusEqualTo(query.getStatus());
        }
        if (Check.notNull(query.getAvailableStatus())) {
            criteria.andAvailableStatusEqualTo(query.getAvailableStatus());
        }

        criteria.andDeletedEqualTo(NOT_DELETED);


        example.orderBy(Sortings.builder(sorts).verify(Column::valueOf).toSql());
        example.setRows(page.getPageSize());
        example.setOffset(page.getFirstIndex());

        return Pagination.create(page, dao.countByExample(example), () -> dao.selectByExampleWithBLOBs(example));
    }

    public DiscountProductWithBLOBs getOnlineById(Integer productId) {
        DiscountProductExample example = new DiscountProductExample();

        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andStatusEqualTo(DiscountProductStatus.ONLINE.real())
                .andDeletedEqualTo(NOT_DELETED);

        return dao.selectOneByExampleWithBLOBs(example);
    }

    public List<DiscountProductWithBLOBs> queryByOnline(QueryOnlineDiscountProductDTO query, Integer size) {
        DiscountProductExample example = new DiscountProductExample();
        DiscountProductExample.Criteria criteria = example.createCriteria();

        criteria.andBrandIdEqualTo(query.getBrandId())
                .andRegionTypeEqualTo(query.getRegionType())
                .andDiscountModeEqualTo(query.getDiscountMode())
                .andStatusEqualTo(DiscountProductStatus.ONLINE.real())
                .andDeletedEqualTo(NOT_DELETED);

        example.orderBy(Column.brandWeight.desc());
        example.setRows(size);

        return dao.selectByExampleWithBLOBs(example);
    }

    public Pagination<DiscountProductWithBLOBs> queryByOnline(QueryOnlineDiscountProductDTO query, Page page) {
        DiscountProductExample example = new DiscountProductExample();
        DiscountProductExample.Criteria criteria = example.createCriteria();

        criteria.andBrandIdEqualTo(query.getBrandId())
                .andRegionTypeEqualTo(query.getRegionType())
                .andDiscountModeEqualTo(query.getDiscountMode())
                .andStatusEqualTo(DiscountProductStatus.ONLINE.real())
                .andDeletedEqualTo(NOT_DELETED);

        example.orderBy(Column.brandWeight.desc());
        example.setRows(page.getPageSize());
        example.setOffset(page.getFirstIndex());

        return Pagination.create(page, dao.countByExample(example), () -> dao.selectByExampleWithBLOBs(example));
    }

    public List<DiscountProductWithBLOBs> queryByServiceType(DiscountProductServiceType serviceType) {
        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andServiceTypeEqualTo(serviceType.real())
                .andDeletedEqualTo(NOT_DELETED);
        return dao.selectByExampleWithBLOBs(example);
    }

    public List<DiscountProductWithBLOBs> queryByServiceTypeAndServiceDataId(DiscountProductServiceType serviceType, String serviceDataId) {
        DiscountProductExample example = new DiscountProductExample();

        DiscountProductExample.Criteria criteria = example.createCriteria();
        criteria.andServiceTypeEqualTo(serviceType.real());
        criteria.andDeletedEqualTo(NOT_DELETED);
        if (Check.notNull(serviceDataId)) {
            criteria.andServiceDataIdEqualTo(serviceDataId);
        }
        return dao.selectByExampleWithBLOBs(example);
    }

    public List<DiscountProductWithBLOBs> queryByBrandId(Integer brandId) {
        DiscountProductExample example = new DiscountProductExample();
        DiscountProductExample.Criteria criteria = example.createCriteria();
        criteria.andBrandIdEqualTo(brandId).andDeletedEqualTo(NOT_DELETED);
        return dao.selectByExampleWithBLOBs(example);
    }

    public void setEnableAvailable(Integer productId, String updateUser) {
        DiscountProductWithBLOBs record = new DiscountProductWithBLOBs();
        record.setAvailableStatus(DiscountProductAvailableStatus.ENABLE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andAvailableStatusEqualTo(DiscountProductAvailableStatus.DISABLE.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.availableStatus,
                Column.updateUser,
                Column.updateTime);
    }

    public void setDisableAvailable(Integer productId, String updateUser) {
        DiscountProductWithBLOBs record = new DiscountProductWithBLOBs();
        record.setAvailableStatus(DiscountProductAvailableStatus.DISABLE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andAvailableStatusEqualTo(DiscountProductAvailableStatus.ENABLE.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record, example,
                Column.availableStatus,
                Column.updateUser,
                Column.updateTime);
    }

    private void verify(DiscountProductWithBLOBs record) {
        DiscountBrand brand = discountBrandManager.getDiscountBrand(record.getBrandId());
        BizAssert.isTrue(Check.notNull(brand), ResultCode.VERIFY.build(10), "品牌不存在");
        BizAssert.isTrue(Check.notNull(DiscountProductRegionType.realValueOf(record.getRegionType())), ResultCode.VERIFY.build(11), "区域类型不支持");
        BizAssert.isTrue(Check.notNull(DiscountProductDiscountMode.realValueOf(record.getDiscountMode())), ResultCode.VERIFY.build(12), "折扣模式不支持");
        BizAssert.isTrue(Check.notNull(DiscountProductServiceType.realValueOf(record.getServiceType())), ResultCode.VERIFY.build(13), "服务类型不支持");
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getName()), ResultCode.VERIFY.build(14), "名称不能为空");

        if (DiscountProductDiscountMode.GIFT_CARD.equal(record.getDiscountMode())) {
            discountProductGiftCardManager.validityVerify(record);
        } else if (DiscountProductDiscountMode.VOUCHERS.equal(record.getDiscountMode())) {
            discountProductVouchersManager.validityVerify(record);
        } else if (DiscountProductDiscountMode.RECHARGE.equal(record.getDiscountMode())) {
            discountProductRechargeManager.validityVerify(record);
        } else {
            BizAssert.throwBizException(ResultCode.BIZ.build(1), "产品不支持的折扣模式");
        }
    }

    void checkIfOnlineAndVerify(Integer productId) {
        DiscountProductWithBLOBs product = getById(productId);
        BizAssert.isTrue(Check.notNull(product), "产品不存在");
        if (DiscountProductStatus.ONLINE.equal(product.getStatus())) {
            onlineVerify(product);
        }
    }

    private void onlineVerify(DiscountProductWithBLOBs product) {
        verify(product);

        // 上线验证
        if (DiscountProductDiscountMode.GIFT_CARD.equal(product.getDiscountMode())) {
            discountProductGiftCardManager.onlineVerify(product);
        } else if (DiscountProductDiscountMode.VOUCHERS.equal(product.getDiscountMode())) {
            discountProductVouchersManager.onlineVerify(product);
        } else if (DiscountProductDiscountMode.RECHARGE.equal(product.getDiscountMode())) {
            discountProductRechargeManager.onlineVerify(product);
        } else {
            BizAssert.throwBizException(ResultCode.BIZ.build(1), "产品不支持的折扣模式");
        }
    }

    @Transactional
    public DiscountProductWithBLOBs create(AddDiscountProductDTO add, String createUser) {
        DiscountProductWithBLOBs record = new DiscountProductWithBLOBs();
        record.setBrandId(add.getBrandId());
        record.setRegionType(add.getRegionType());
        record.setDiscountMode(add.getDiscountMode());
        record.setServiceType(add.getServiceType());
        record.setServiceDataId(add.getServiceDataId());
        record.setName(add.getName());
        record.setSubTitle(add.getSubTitle());
        record.setImage(add.getImage());
        record.setDescribe(add.getDescribe());
        record.setUseInformation(add.getUseInformation());
        record.setShelfLifeStrategy(add.getShelfLifeStrategy());
        record.setShelfLifeDescribe(add.getShelfLifeDescribe());
        record.setFixedEndShelfLife(add.getFixedEndShelfLife());
        record.setDynamicShelfLifeType(add.getDynamicShelfLifeType());
        record.setDynamicShelfLifeValue(add.getDynamicShelfLifeValue());
        record.setBrandWeight(0);
        record.setIsNew(true);
        record.setStatus(DiscountProductStatus.EDITING.real());
        record.setAvailableStatus(DiscountProductAvailableStatus.DISABLE.real());
        record.setDeleted(NOT_DELETED);
        record.setCreateUser(createUser);
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateUser(createUser);
        record.setUpdateTime(Date.from(Instant.now()));

        verify(record);

        dao.insert(record);
        // 创建礼品卡信息
        if (DiscountProductDiscountMode.GIFT_CARD.equal(record.getDiscountMode())) {
            discountProductGiftCardManager.create(record, createUser);
        } else if (DiscountProductDiscountMode.VOUCHERS.equal(record.getDiscountMode())) {
            discountProductVouchersManager.create(record, createUser);
        } else if (DiscountProductDiscountMode.RECHARGE.equal(record.getDiscountMode())) {
            discountProductRechargeManager.create(record, createUser);
        }
        return record;
    }

    @Transactional
    public void update(Integer productId, EditDiscountProductDTO edit, String updateUser) {
        DiscountProductWithBLOBs record = getById(productId);
        record.setName(edit.getName());
        record.setSubTitle(edit.getSubTitle());
        record.setImage(edit.getImage());
        record.setDescribe(edit.getDescribe());
        record.setUseInformation(edit.getUseInformation());
        record.setShelfLifeStrategy(edit.getShelfLifeStrategy());
        record.setShelfLifeDescribe(edit.getShelfLifeDescribe());
        record.setFixedEndShelfLife(edit.getFixedEndShelfLife());
        record.setDynamicShelfLifeType(edit.getDynamicShelfLifeType());
        record.setDynamicShelfLifeValue(edit.getDynamicShelfLifeValue());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        verify(record);

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.name,
                Column.subTitle,
                Column.image,
                Column.describe,
                Column.useInformation,
                Column.shelfLifeStrategy,
                Column.shelfLifeDescribe,
                Column.fixedEndShelfLife,
                Column.dynamicShelfLifeType,
                Column.dynamicShelfLifeValue,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(2), "更新产品信息失败");

        checkIfOnlineAndVerify(productId);
    }
    
    public void updateMarketing(Integer productId, EditDiscountProductOperationStrategyDTO edit, String updateUser) {
        DiscountProductWithBLOBs record = new DiscountProductWithBLOBs();
        record.setStartSalesDate(edit.getStartSalesDate());
        record.setEndSalesDate(edit.getEndSalesDate());
        record.setBrandWeight(edit.getBrandWeight());
        record.setIsNew(edit.getIsNew());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.startSalesDate,
                Column.endSalesDate,
                Column.brandWeight,
                Column.isNew,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(2), "更新产品营销信息失败");
    }

    @Transactional
    public void online(Integer productId, String updateUser) {
        DiscountProductWithBLOBs product = getById(productId);
        BizAssert.isTrue(Check.notNull(product), ResultCode.VERIFY.build(10), "产品不存在");
        BizAssert.isTrue(DiscountProductStatus.canOnline(product), ResultCode.BIZ.build(1), "产品状态无法上线");

        onlineVerify(product);

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andStatusEqualTo(product.getStatus())
                .andDeletedEqualTo(NOT_DELETED);

        product.setStatus(DiscountProductStatus.ONLINE.real());
        product.setUpdateUser(updateUser);
        product.setUpdateTime(Date.from(Instant.now()));

        int row = dao.updateByExampleSelective(product,
                example,
                Column.status,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(2), "产品上线失败");
    }

    public void offline(Integer productId, String updateUser) {
        DiscountProductWithBLOBs product = getById(productId);
        BizAssert.isTrue(Check.notNull(product), ResultCode.VERIFY.build(10), "产品不存在");
        BizAssert.isTrue(DiscountProductStatus.canOffline(product), ResultCode.BIZ.build(1), "产品状态无法下线");

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andStatusEqualTo(product.getStatus())
                .andDeletedEqualTo(NOT_DELETED);

        product.setStatus(DiscountProductStatus.OFFLINE.real());
        product.setUpdateUser(updateUser);
        product.setUpdateTime(Date.from(Instant.now()));

        int row = dao.updateByExampleSelective(product,
                example,
                Column.status,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(2), "产品下线失败");
    }

    public void delete(Integer productId, String updateUser) {
        DiscountProductWithBLOBs product = getById(productId);
        BizAssert.isTrue(Check.notNull(product), ResultCode.VERIFY.build(10), "产品不存在");
        BizAssert.isTrue(DiscountProductStatus.canDel(product), ResultCode.BIZ.build(1), "产品状态无法删除");

        DiscountProductExample example = new DiscountProductExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andStatusEqualTo(product.getStatus())
                .andDeletedEqualTo(NOT_DELETED);

        product.setDeleted(IS_DELETED);
        product.setUpdateUser(updateUser);
        product.setUpdateTime(Date.from(Instant.now()));

        int row = dao.updateByExampleSelective(product,
                example,
                Column.deleted,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(2), "产品删除失败");

        // TODO 删除关联的数据表
    }

}